﻿using System;
using System.Collections.Generic;
using System.Text;
using Sofire.Data.XSql;

namespace Sofire.Data
{
 
    /// <summary>
    /// 表示一个 XSql 参数的集合。
    /// </summary>
    public class XSqlParameterCollection : ICollection<ExecuteParameter>
    {
        private readonly Dictionary<string, ExecuteParameter> Inner;

        /// <summary>
        /// 初始化一个 <see cref="Sofire.Data.XSqlParameterCollection"/> 的新实例。
        /// </summary>
        public XSqlParameterCollection() : this(4) { }
        /// <summary>
        /// 指定可包含的初始元素数，初始化 <see cref="Sofire.Data.XSqlParameterCollection"/> 的新实例。
        /// </summary>
        /// <param name="capacity">可包含的初始元素数。</param>
        public XSqlParameterCollection(int capacity)
        {
            Inner = new Dictionary<string, ExecuteParameter>(capacity, StringComparer.CurrentCultureIgnoreCase);
        }

        internal event Func<string, string> NameConverter;

        private string GetName(string name)
        {
            if(NameConverter != null)
            {
                name = NameConverter(name);
                if(string.IsNullOrEmpty(name)) throw new ArgumentNullException("NameConvert");
            }
            return name;
        }

        /// <summary>
        /// 获取指定参数名称的参数。
        /// </summary>
        /// <param name="name">参数名称。</param>
        /// <returns>返回一个参数，或一个 null 值。</returns>
        public virtual ExecuteParameter this[string name]
        {
            get
            {
                ExecuteParameter p;
                if(this.Inner.TryGetValue(this.GetName(name), out p)) return p;
                return null;
            }
        }

        /// <summary>
        /// 获取指定参数名称的值。
        /// </summary>
        /// <param name="name">参数名称。</param>
        /// <returns>返回参数的值，或一个 null 值。</returns>
        public object GetValue(string name)
        {
            ExecuteParameter p = this[name];
            if(p != null) return p.Value;
            return null;
        }

        /// <summary>
        /// 获取一个值，指示当前是否处于动态绑定的状态（如 foreach 节点）。
        /// </summary>
        internal bool IsDynamicBind
        {
            get
            {
                return NameConverter != null;
            }
        }

        /// <summary>
        /// 创建一个 <see cref="Sofire.Data.XSql.XSqlBindItem"/> 项。
        /// </summary>
        /// <param name="expression">表达式</param>
        /// <returns>返回一个 <see cref="Sofire.Data.XSql.XSqlBindItem"/> 项。</returns>
        internal XSqlBindItem CreateBindItem(string expression)
        {
            var item = new XSqlBindItem(expression);

            if(NameConverter != null) item.Name = NameConverter(item.Name);

            return item;
        }

        #region AddArray

        /// <summary>
        /// 添加并返回一个新的参数，该枚举参数将会自动添加相应的参数集合。
        /// </summary>
        /// <param name="name">参数名称。</param>
        /// <param name="values">参数值。</param>
        /// <returns>返回当前集合对象。</returns>
        public XSqlParameterCollection AddArray(string name, params string[] values)
        {
            return this.AddArray(name, (System.Collections.IEnumerable)values);
        }
        /// <summary>
        /// 添加并返回一个新的参数，该枚举参数将会自动添加相应的参数集合。
        /// </summary>
        /// <param name="name">参数名称。</param>
        /// <param name="values">参数值。</param>
        /// <returns>返回当前集合对象。</returns>
        public XSqlParameterCollection AddArray(string name, params int[] values)
        {
            return this.AddArray(name, (System.Collections.IEnumerable)values);
        }
        /// <summary>
        /// 添加并返回一个新的参数，该枚举参数将会自动添加相应的参数集合。
        /// </summary>
        /// <param name="name">参数名称。</param>
        /// <param name="values">参数值。</param>
        /// <returns>返回当前集合对象。</returns>
        public XSqlParameterCollection AddArray(string name, params double[] values)
        {
            return this.AddArray(name, (System.Collections.IEnumerable)values);
        }
        /// <summary>
        /// 添加并返回一个新的参数，该枚举参数将会自动添加相应的参数集合。
        /// </summary>
        /// <param name="name">参数名称。</param>
        /// <param name="values">参数值。</param>
        /// <returns>返回当前集合对象。</returns>
        public XSqlParameterCollection AddArray(string name, params decimal[] values)
        {
            return this.AddArray(name, (System.Collections.IEnumerable)values);
        }
        /// <summary>
        /// 添加并返回一个新的参数，该枚举参数将会自动添加相应的参数集合。
        /// </summary>
        /// <param name="name">参数名称。</param>
        /// <param name="values">参数值。</param>
        /// <returns>返回当前集合对象。</returns>
        public XSqlParameterCollection AddArray(string name, params object[] values)
        {
            return this.AddArray(name, (System.Collections.IEnumerable)values);
        }
        /// <summary>
        /// 添加并返回一个新的参数，该枚举参数将会自动添加相应的参数集合。
        /// </summary>
        /// <typeparam name="T">值的参数类型。</typeparam>
        /// <param name="name">参数名称。</param>
        /// <param name="values">参数值。</param>
        /// <returns>返回当前集合对象。</returns>
        public XSqlParameterCollection AddArray<T>(string name, params T[] values)
        {
            return this.AddArray(name, (System.Collections.IEnumerable)values);
        }

        /// <summary>
        /// 添加并返回一个新的参数，该枚举参数将会自动添加相应的参数集合。
        /// </summary>
        /// <param name="name">参数名称。</param>
        /// <param name="values">参数值。</param>
        /// <returns>返回当前集合对象。</returns>
        public XSqlParameterCollection AddArray(string name, System.Collections.IEnumerable values)
        {
            //- 在这里进行数组的分离，是为了缓存机制
            int index = 0;
            var p = new ExecuteParameter(name, values);
            this.Add(p);
            foreach(var item in values)
            {
                p = new ExecuteParameter(name + "_" + (index++), item);
                this.Add(p);
            }
            return this;
        }

        #endregion


        /// <summary>
        /// 添加并返回一个新的参数。
        /// </summary>
        /// <param name="name">参数名称。</param>
        /// <param name="value">参数值。</param>
        /// <returns>返回当前集合对象。</returns>
        public XSqlParameterCollection Add(string name, object value)
        {
            this.Add(new ExecuteParameter(name, value));
            return this;
        }

        /// <summary>
        /// 添加一个新的参数。
        /// </summary>
        /// <param name="item">参数。</param>
        public void Add(ExecuteParameter item)
        {
            if(item == null) return;
            if(string.IsNullOrEmpty(item.Name)) throw new ArgumentNullException("item.Name");
            this.Inner[item.Name] = item;
        }

        /// <summary>
        /// 添加当前集合包含指定的参数。
        /// </summary>
        /// <param name="item">参数。</param>
        /// <returns>如果存在则返回 true，否则返回 false。</returns>
        public bool Remove(ExecuteParameter item)
        {
            if(item == null) throw new ArgumentNullException("item");
            return this.Inner.Remove(item.Name);
        }
        /// <summary>
        /// 添加当前集合包含指定的参数名称。
        /// </summary>
        /// <param name="name">参数名称。</param>
        /// <returns>如果存在则返回 true，否则返回 false。</returns>
        public bool Remove(string name)
        {
            return this.Inner.Remove(name);
        }

        /// <summary>
        /// 清空所有参数。
        /// </summary>
        public void Clear()
        {
            this.Inner.Clear();
        }

        /// <summary>
        /// 确定当前集合包含指定的参数名称。
        /// </summary>
        /// <param name="name">查找的参数名称。</param>
        /// <returns>如果存在则返回 true，否则返回 false。</returns>
        public bool Contains(string name)
        {
            return this.Inner.ContainsKey(name);
        }
        /// <summary>
        /// 确定当前集合包含指定的参数。
        /// </summary>
        /// <param name="item">查找的参数。</param>
        /// <returns>如果存在则返回 true，否则返回 false。</returns>
        public bool Contains(ExecuteParameter item)
        {
            if(item == null) throw new ArgumentNullException("item");
            return this.Inner.ContainsKey(item.Name);
        }

        /// <summary>
        /// 获取当前参数的数量。
        /// </summary>
        public int Count
        {
            get { return this.Inner.Count; }
        }


        void ICollection<ExecuteParameter>.CopyTo(ExecuteParameter[] array, int arrayIndex)
        {
            this.Inner.Values.CopyTo(array, arrayIndex);
        }

        bool ICollection<ExecuteParameter>.IsReadOnly
        {
            get { return false; }
        }

        #region IEnumerable<ExecuteParameter> 成员

        IEnumerator<ExecuteParameter> IEnumerable<ExecuteParameter>.GetEnumerator()
        {
            return this.Inner.Values.GetEnumerator();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return this.Inner.Values.GetEnumerator();
        }

        #endregion

        private Stack<object[]> _expressionParrameters;
        private readonly object ExpressionParrametersSyncObject = new object();

        /// <summary>
        /// 插入一个表达式参数集。
        /// </summary>
        /// <param name="parameters">表达式参数集。</param>
        internal void PushExpressionParrameters(object[] parameters)
        {
            if(_expressionParrameters == null)
                lock(ExpressionParrametersSyncObject) _expressionParrameters = new Stack<object[]>();
            _expressionParrameters.Push(parameters);
        }

        /// <summary>
        /// 移除并返回一个表达式参数集。
        /// </summary>
        /// <returns>返回一个表达式参数集。</returns>
        internal object[] PopExpressionParrameters()
        {
            if(_expressionParrameters == null) throw new ArgumentException("未定义的表达式参数！", "expression");
            if(_expressionParrameters.Count == 0) return null;
            return _expressionParrameters.Pop();
        }

        /// <summary>
        /// 返回表示参数集合的字符串形式。
        /// </summary>
        public override string ToString()
        {
            StringBuilder builder = new StringBuilder();
            foreach(var item in this.Inner.Values)
            {
                builder.AppendLine(item.ToString());
            }
            return builder.ToString();
        }
    }

    /// <summary>
    /// 表示按需参数事件委托。
    /// </summary>
    /// <param name="collection">XSql 参数的集合。</param>
    /// <param name="name">参数的名称。</param>
    /// <returns>参数的值。</returns>
    public delegate object DemandXSqlParameterEventHandler(DemandXSqlParameterCollection collection, string name);

    /// <summary>
    /// 表示一个按需的 XSql 参数的集合。
    /// </summary>
    public class DemandXSqlParameterCollection : XSqlParameterCollection
    {
        /// <summary>
        /// 初始化一个 <see cref="Sofire.Data.DemandXSqlParameterCollection"/> 的新实例。
        /// </summary>
        public DemandXSqlParameterCollection() : base(4) { }
        /// <summary>
        /// 指定可包含的初始元素数，初始化 <see cref="Sofire.Data.DemandXSqlParameterCollection"/> 的新实例。
        /// </summary>
        /// <param name="capacity">可包含的初始元素数。</param>
        public DemandXSqlParameterCollection(int capacity) : base(capacity) { }

        /// <summary>
        /// 当集合找不到名称时，引发起的按需参数事件。
        /// </summary>
        public event DemandXSqlParameterEventHandler Demand;

        /// <summary>
        /// 当集合找不到名称时，引发起的按需参数事件。
        /// </summary>
        /// <param name="name">参数的名称。</param>
        /// <returns>参数。</returns>
        protected virtual ExecuteParameter OnDemand(string name)
        {
            if(this.Demand == null) return null;
            var o = this.Demand(this, name);
            if(o == null) return null;
            var p = new ExecuteParameter(name, o);
            this.Add(p);
            return p;
        }

        /// <summary>
        /// 获取指定参数名称的参数。
        /// </summary>
        /// <param name="name">参数名称。</param>
        /// <returns>返回一个参数，或一个 null 值。</returns>
        public override ExecuteParameter this[string name]
        {
            get
            {
                return base[name] ?? this.OnDemand(name);
            }
        }

    }
}
